from typing import Optional
from datetime import timedelta, datetime, timezone
from jose import jwt
from fastapi import Header, HTTPException, status
from app.setting.setting import config
from app.api.schemas.token import Token


# 生成token
def create_token(data: dict, expires_delta: timedelta=None):
    """
    # 生成token
    :param subject: 保存到token的值
    :param expires_delta: 过期时间
    :return:
    """
    to_encode = data.copy()
    if expires_delta:
        # 使用带时区感知的对象来表示 UTC 时间
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        # 使用带时区感知的对象来表示 UTC 时间
        expire = datetime.now(timezone.utc) + timedelta(minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES)
    # 添加失效时间
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, config.SECRET_KEY, algorithm=config.ALGORITHM)

    return encoded_jwt

# 验证token
def check_jwt_token(x_token: str = Header(...)):
    """
    验证token
    :param x_token: 待验证的 JWT 令牌
    :return: 令牌的有效负载
    """
    try:
        payload = jwt.decode(x_token, config.SECRET_KEY, algorithms=config.ALGORITHM)
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={
                'status': 5000,
                'message': "token过期，请重新登录",
                'data': "Token Error: Expired Signature",
            }
        )
    except jwt.JWTError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={
                'status': 5000,
                'message': "token验证失败，请重新登录",
                'data': f"Token Error: {str(e)}",
            }
        )


# 刷新token
def refresh_token(refresh_token: Optional[str] = Header(...)):
    """
    验证refresh_token，通过后刷新token和refresh_token
    :param token:
    :return: 刷新后token
    """
    try:
        payload = jwt.decode(refresh_token, config.SECRET_KEY, algorithms=config.ALGORITHM)

        # 过期时间
        access_token_expires = timedelta(minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES)
        refresh_token_expires = timedelta(minutes=config.REFRESH_TOKEN_EXPIRE_MINUTES)

        access_token = create_token(
            data=payload, expires_delta=access_token_expires
        )

        refresh_token = create_token(
            data=payload, expires_delta=refresh_token_expires
        )

        token = Token(userName=payload.get('sub'), access_token=access_token, refresh_token=refresh_token)

        return token

    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={
                'code': 5000,
                'message': "Token Error",
                'data': "refresh_token过期",
            }
        )
    except jwt.JWTError as e:
        return HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={
                'code': 5000,
                'message': "Token Error",
                'data': "refresh_token验证失败",
            }
        )
